package com.zjsru.plan2023.oneday;

import java.util.Arrays;

/**
 * @Author: cookLee
 * @Date: 2023-12-03
 * 可获得的最大点数
 */
public class MaxScore {

    /**
     * 主
     * \
     * 输入：cardPoints = [1,2,3,4,5,6,1], k = 3
     * 输出：12
     * 解释：第一次行动，不管拿哪张牌，你的点数总是 1 。但是，先拿最右边的卡牌将会最大化你的可获得点数。最优策略是拿右边的三张牌，最终点数为 1 + 6 + 5 = 12 。
     * \
     * 输入：cardPoints = [2,2,2], k = 2
     * 输出：4
     * 解释：无论你拿起哪两张卡牌，可获得的点数总是 4 。
     * \
     * 输入：cardPoints = [9,7,7,9,7,7,9], k = 7
     * 输出：55
     * 解释：你必须拿起所有卡牌，可以获得的点数为所有卡牌的点数之和。
     * \
     * @param args args
     */
    public static void main(String[] args) {
        MaxScore maxScore = new MaxScore();
        int[] cardPoints = new int[]{1, 2, 3, 4, 5, 6, 1};
        int k = 3;
        System.out.println(maxScore.maxScore(cardPoints, k));
    }

    /**
     * 最高分数: 滑动窗口 构建出一个n-k的窗口记录值 与总数相减后最大即是答案
     *
     * @param cardPoints 卡积分
     * @param k          k
     * @return int
     */
    public int maxScore(int[] cardPoints, int k) {
        //非答案范围的滑动窗口
        int len = cardPoints.length - k;
        //获取滑动窗口内总和
        int sum = 0;
        for (int i = 0; i < len; i++) {
            sum += cardPoints[i];
        }
        //窗口内可以获取的最小值
        int minSum = sum;
        for (int i = len; i < cardPoints.length; i++) {
            //移动窗口，先加入新的值，删除原来的值
            sum += cardPoints[i];
            sum -= cardPoints[i - len];
            //留下最小值
            minSum = Math.min(minSum, sum);
        }
        //差值即是答案
        return Arrays.stream(cardPoints).sum() - minSum;
    }

}
